
#from sd.kernel.Pipes.Services import ServicePool
from singleton import singleton
#from sd.kernel.Containers.Container import Containerize, AnonymusContainer

import json, time

@singleton
class Registry:
    system_table = "__RegistrySettings"

    def __init__(self):
        self.load()
        if self.registry == {}:
            self.Call(None, ("create_table", "__RegistrySettings"))
            self.Call(None, ("set", "__RegistrySettings", "table", "__RegistrySettings"))
            self.Call(None, ("set", "__RegistrySettings", "file", "registry.rdb"))
            self.Call(None, ("set", "__RegistrySettings", "compression", False))

    registry = {}

    def Call(self, pipe_id, data):
        operations = {
            "get": self.get_record,
            "create_table": self.create_table,
            "set": self.set_record,
            "delete_table": self.delete_table,
            "delete_record": self.delete_record,
            "get_all_records": self.get_all_records,
            "get_tables": self.get_tables,
            "select": self.select_records,
            "save": self.save,
            "load": self.load,
            "execute": self.execute_command,
            "insert": self.insert
        }
        if not isinstance(data, tuple):
            return False, "data must be a tuple"

        operation, *args = data
        if operation not in operations:
            return False, f"Unknown operation: {operation}"

        try:
            operation_func = operations[operation]
            result = operation_func(pipe_id, *args)
            return True, result
        except Exception as e:
            return False, str(e)

    #@Containerize(AnonymusContainer)
    def save(self, name="/db.reg"):
        with open(name, 'wb') as file:
            #file.write(zlib.compress(json.dumps(self.registry).encode()))
            json.dump(self.registry, file)

    def load(self, name="/db.reg"):
        try:
            with open(name, 'rb') as file:
                #self.registry = json.dumps(zlib.decompress(file.read()).decode())
                self.registry = json.load(file)
        except:
            self.registry = {}

    def get_record(self, pipe_id, table_name, key):
        table = self.registry.get(table_name, {})
        return table.get(key, False)

    def create_table(self, pipe_id, table_name):
        self.registry[table_name] = {}
        self.save()
        return True

    def set_record(self, pipe_id, table_name, key, value):
        table = self.registry.get(table_name, {})
        table[key] = value
        self.registry[table_name] = table
        self.save()
        return True

    def get_tables(self, _=None):
        return list(self.registry.keys())

    def delete_table(self, pipe_id, table_name):
        if table_name in self.registry:
            del self.registry[table_name]
            self.save()
            return True
        self.save()
        return False

    def delete_record(self, pipe_id, table_name, key):
        table = self.registry.get(table_name, {})
        if key in table:
            del table[key]
            self.registry[table_name] = table
            self.save()
            return True
        self.save()
        return False

    def get_all_records(self, pipe_id, table_name):
        table = self.registry.get(table_name, {})
        return table.copy()

    def select_records(self, pipe_id, table_name, condition):
        table = self.registry.get(table_name, {})
        selected_records = {}
        for key, value in table.items():
            if condition(value):
                selected_records[key] = value
        return selected_records

    def insert(self, pipe_id, table_name, records_dict):
        table = self.registry.get(table_name, {})
        for key, value in records_dict.items():
            table[key] = value
        self.registry[table_name] = table
        self.save()
        return True

    def execute_command(self, pipe_id, command_str):
        start_time = time.ticks_ms()
        args = command_str.split()
        operation = args[0]
        params = args[1:]

        if operation == "get":
            table_name, key = params
            success, result = self.Call(None, (operation, table_name, key))

        elif operation == "create_table":
            table_name = params[0]
            success, result = self.Call(None, (operation, table_name))

        elif operation == "set":
            params = command_str.split(' ', 3)
            table_name, key, value = params[1:4]
            #print(table_name, key, value)
            success, result = self.Call(None, (operation, table_name, key, eval(value)))

        elif operation == "delete_record":
            table_name, key = params
            success, result = self.Call(None, (operation, table_name, key))

        elif operation == "delete_table":
            table_name = params[0]
            success, result = self.Call(None, (operation, table_name))

        elif operation == "select":
            table_name = params[0]
            condition = ' '.join(params[1:])
            if condition in ['*', 'any', 'all']:
                condition = 'True'
            condition = eval(f"lambda record: {condition}")
            success, result = self.Call(None, (operation, table_name, condition))

        elif operation == "get_tables":
            success, result = self.Call(None, (operation,))

        else:
            success = False
            result = f"Unknown operation: {operation}"

        execution_time = time.ticks_ms() - start_time
        return success, result, execution_time

#ServicePool().CreateService("Registry", lambda _, d: Registry().execute_command(_, d)) # Регистрируем новый сервис

#print(ServicePool().CallService("Registry", "select __RegistrySettings *"))  # Обращаемся к нему

registry = Registry()


def main():
    print('''Welcome to the Registry DB CLI

Type 'help' for a list of available commands.

Registry DB CLI>''')
    sym = '-> '
    while True:
        try:
            command_str = input(sym)

            if not command_str: continue
            if command_str == "exit":
                print("Goodbye!")
                break

            success, execution_result, execution_time = registry.execute_command(None, command_str)
            result = execution_result
            if type(execution_result) is list: result = ', '.join(result)
            if type(execution_result) is dict:
                result = ""
                for k in execution_result:
                    result += f"    - \x1b[36;1m{k}\x1b[0m: \x1b[37;1m{str(execution_result[k])}\x1b[0m (\x1b[35;1m{type(execution_result[k]).__name__}\x1b[0m)\n"
            if type(execution_result) is bool:
                result = '\x1b[32;1mOK\x1b[0m' if execution_result else '\x1b[31;1mERROR\x1b[0m'

            print(f"{result}\n" if success else f"Error: {result}\n")

            print(f"Execution time: {execution_time:.2f} ms.")

        except Exception as e:
            print(f"Error: {e}")
            break

#registry.execute_command(None, f"create_table bench")

#for i in range(2048):
#    registry.execute_command(None, f"set bench datachunk_{i} {hash(str(i))}")
#main()
registry.Call(None, ("create_table", "users"))

# Вставка записей в таблицу
records = {
    "user1": {"name": "Alice", "age": 25},
    "user2": {"name": "Bob", "age": 30},
    "user3": {"name": "Charlie", "age": 35}
}
registry.insert(None, "users", records)

# Получение всех записей из таблицы
all_records = registry.Call(None, ("get_all_records", "users"))
print(all_records)

main()

